//-----------------------------------------
// Declaration of the Header files required.
//------------------------------------------


#include "copyright.h"
#include "system.h"
#include "synch.h"
#include "list.h"

//----------------------------------------------------------
// Declare global variables and Data Structures Below
//----------------------------------------------------------

#define MAX_NO_OF_CLERKS 5
#define MAX_NO_OF_CASHREGISTERS 5
#define MAX_NO_OF_CUSTOMERS 1000
#define MAX_NO_OF_AISLE 10
#define MAX_NO_SB 50



int testcase;
int noOfClerks;		// values will change dynamically
int noOfCashReg;
int noOfCustomers;
int noOfStockBoys;
int noOfAisle;
//Customer data sturcture
typedef struct customer
{
	int noOfItemsToBePurchased;
	int itemsToBePurchased[10];
	bool customerReturning;
	customer()
	{
		noOfItemsToBePurchased=(int)((rand()%10)+1);
		for(int i=0;i<noOfItemsToBePurchased;i++)
		{
			itemsToBePurchased[i]=(int)(rand()%10);
		}
		if(rand()%5==4){
			customerReturning=true;
		}
		else{
			customerReturning=false;
		}
	}

}customerDataTemplate;

customerDataTemplate customerData[MAX_NO_OF_CUSTOMERS];


// cashregister data-structure

typedef struct cashregister
{

	// only clerkLock[] should access this data member
	int customerAmount;
	// only manager_CashRegisterLock should access this data member
	int totalAmount;
	//totalsales at this cash counter
	int totalSalesAtCashRegister;

	cashregister(){

		customerAmount = 0;
		totalAmount = 0;
		totalSalesAtCashRegister = 0;
	}
};



cashregister cashRegister[MAX_NO_OF_CASHREGISTERS];


const int itemsInStoreInfo[MAX_NO_OF_AISLE]={1,2,3,4,5,6,7,8,9,10} ;

//------------------------------------------------------------------------
// Declare Locks, CV and Monitor Variables for Customer/Clerk Interaction
//------------------------------------------------------------------------

enum clerkStatusEnum{CLERK_BUSY, CLERK_ONBREAK, CLERK_COMING_FROM_BREAK, CLERK_FREE};



//Lock for mutual exclusion on entering line.
Lock* clerkLineLock;			
//Locks for each clerk interaction.
Lock* clerkLock[MAX_NO_OF_CLERKS];	
//condition to wait on a line for checkout
Condition* clerkLineCV[MAX_NO_OF_CLERKS];		
//condition to interaction btw one customer and clerk at a time.
Condition* clerkTalkCV[MAX_NO_OF_CLERKS];		
// condition variable for the customer to wait untill manager takes action for no clerk problem.
Condition* noClerkButtonCV;
//Condition Variable for Clerks waiting on a break
Condition* clerkOnBreakCV;
// maintains the length of each line.
int clerkLineLength[MAX_NO_OF_CASHREGISTERS]={0,0,0,0,0};
//maintains the status of each clerk.
clerkStatusEnum clerkStatus[MAX_NO_OF_CLERKS]={CLERK_FREE,CLERK_FREE,CLERK_FREE,CLERK_FREE,CLERK_FREE};
//For the manager to check that there is no clerk to serve the Customer and that customer are waiting.
bool noClerkAvailable=FALSE;

//all to be used for checkout process. To be used under clerkLock[i].
int itemId[MAX_NO_OF_CLERKS]={-1,-1,-1,-1,-1};
//to notify that the last item will be processed for each customer/clerk/cash register transaction.
bool lastItem[MAX_NO_OF_CLERKS]={FALSE,FALSE,FALSE,FALSE,FALSE};
//to store the value of customer id so that clerk and cash register know who they are serving.
int customerId[MAX_NO_OF_CLERKS]={-1,-1,-1,-1,-1};
//to store the total bill amount for each customer/clerk/cash register transaction.
int receiptBillAmount[MAX_NO_OF_CLERKS]={-1,-1,-1,-1,-1};
// will help each clerk and cash register know if the customer wants to buy or return items.
bool isCustomerReturning[MAX_NO_OF_CLERKS]={FALSE,FALSE,FALSE,FALSE,FALSE};//to check if it is buying or returning customer
//to be used with clerkLineLock
int signalingClerk=-1; // To store Id of clerk who call manager when line is above 4




//------------------------------------------------------------------------
// Declare Locks, CV and Monitor Variables for Clerk/CashRegister Interaction
//------------------------------------------------------------------------

//All these variables would be modified with the clerkLock[i]
//differnet states a cash register can be in.
enum cashRegisterStatusEnum{NOT_SET, CLERK_WAITING, CASHREG_WAITING };
//for clerk and cash reg interaction.
Condition* cashRegisterCV[MAX_NO_OF_CASHREGISTERS];
//status array for all cash registers.
cashRegisterStatusEnum cashRegisterStatus[MAX_NO_OF_CASHREGISTERS] = {NOT_SET,NOT_SET,NOT_SET,NOT_SET,NOT_SET};


//------------------------------------------------------------------------------
// Declare Locks, CV and Monitor Variables for Manager/Cash Register Interaction
//------------------------------------------------------------------------------

//Lock for Mutual Exclusion between Manager and Cash Register
//No CV's or Monitor variables between them
Lock* manager_CashRegisterLock[MAX_NO_OF_CASHREGISTERS];
int amountNeeded[MAX_NO_OF_CASHREGISTERS]={0,0,0,0,0};//amount needed by cash register to give to customer returning items
Condition* cashRegisterWaitingCV[MAX_NO_OF_CASHREGISTERS];

//------------------------------------------------------------------------------
// Declare Locks, CV and Monitor Variables for Customer/StockBoy/Aisle Interaction
//------------------------------------------------------------------------------


// lock to check the status of stock boy maintianing the mutual exclusion.
Lock* sbStatusLock;
/// sbStatus for maintianing the status of each stockboy	-1=free		-2=on break	>=0 In store doing stuff
int sbStatus[MAX_NO_SB]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};  
//maintain the length of the customer needing help in each aisle.
int aisleHelpLineLength[MAX_NO_OF_AISLE]={0,0,0,0,0,0,0,0,0,0};
// to wait on the aisle for help.
Condition* aisleHelpCV[MAX_NO_OF_AISLE];

//access stock room one at time.
Lock* stockRoomLock;
int stockRoomStatus = -1;//to be used with stockRoomLock
Condition* stockRoomWaitCV;

//access the restock list maintianing the data consistency.
Lock* reStockListLock;
// list of items to be restocked.
List* reStockList;

//lock for updating the Qty on each aisle.
Lock* aisleQtyLock[MAX_NO_OF_AISLE];
//maintain the Qty on each aisle
int aisleQty[MAX_NO_OF_AISLE]={3,3,3,3,3,3,3,3,3,3};
//if the Qty on aisle is empty, wait till restocked.
Condition* aisleEmptyCV[MAX_NO_OF_AISLE];


// Lock for the button when no SB available.
Lock* noSBPushButtonLock;
// customers wait till SB is woken by manager.
Condition* noSBPushButtonCV;
//stock boys wait till SB is woken by manager.
Condition* sbOnBreakCV;
// maintains the length of the line waiting on the pushbutton.
int noSBPushButtonLineLength=0;

// lock on each SB.
Lock* sbLock[MAX_NO_SB];
// wait on SB.
Condition* sbCV[MAX_NO_SB];
//For the Customer and SB ping pong.
int sbCustQA[MAX_NO_SB][2];


//------------------------------------------------------------------------------
// Declare Locks, CV and Monitor Variables for Manager Interaction
//------------------------------------------------------------------------------
//variable modified by customers and read by manager to make note of end of simulation
int totalcustomersexited=0;
//Customer waiting when all clerks are on break
Condition *custWaitingCV;// This CV should be used with clerkLineLock
bool allClerksOnBreak=false;
//Clerks signaling manager to wakeup another clerk if their linelength>4
bool wakeUpAClerk=false;// This CV should be used with clerkLineLock







//----------------------------------------------
// Functions for all different types of Threads
//----------------------------------------------

//--------Customer Thread Starts Here-----------///

void Customer(int threadId)
{
	//For finding the shortest length. Also the Total customers in a line cannot be more than 99999
	int shortestLineLength=100000;

	int *restockItem;

	// For finding the index of the line with shortest length.	
	int shortestLineIndex=-1;
	bool sbFound=FALSE;

	//If customer is going to return items then just bypass the item finding code and go to Clerk
	if(customerData[threadId].customerReturning){
		printf("Customer [%d] needs to return [%d] no.of items.\n",threadId, customerData[threadId].noOfItemsToBePurchased);
		goto liningForClerk;
	}
	//===================================Customer's Item Fetching code below===================================
	
	printf("Customer [%d] wants to buy [%d] no.of items. \n",threadId,customerData[threadId].noOfItemsToBePurchased);

	for(int currentItemId=0;currentItemId<customerData[threadId].noOfItemsToBePurchased;currentItemId++)
	{
		// Generating the 25% failure probablity for finding the item.
		int itemAisleId=customerData[threadId].itemsToBePurchased[currentItemId];
		int failureProbablity=(rand()%4);
		sbFound=FALSE;

		//=============================Finding stock boy code below=============================
		if(failureProbablity==1)
		{
			//We need to get help from the stockboy
			printf("Customer [%d] is not able to find item [%d] and is searching for StockBoy.\n",threadId,currentItemId);
			sbStatusLock->Acquire();

			// Finding a stockboy for help
			int counter=0;
			int mySB=itemAisleId;

			//Iterating for each stockboy
			while(counter!=noOfStockBoys)
			{

				//If sbStatus >= 0, it indicates that the stockboy is in aisle , so select that stockboy.
				if(sbStatus[mySB]>=0)
				{ 
					int currentAisleNumber = (sbStatus[mySB]%MAX_NO_OF_AISLE);
					sbFound=TRUE;
					aisleHelpLineLength[currentAisleNumber]++;
					aisleHelpCV[currentAisleNumber]->Wait(sbStatusLock);

					for(int y=0;y<noOfStockBoys;y++)
					{
						if((sbStatus[y])==(currentAisleNumber+MAX_NO_OF_AISLE))
						{

							sbStatus[y]=sbStatus[y]-MAX_NO_OF_AISLE;
							mySB=y;
							break;
						}
					}

					//sbStatusLock->Release(); It's redundant since there is release after the while loop
					break;
				}
				mySB=(mySB+1)% noOfStockBoys;
				counter++;
			}
			sbStatusLock->Release();

			
			//=============================No SB. PushButton code below=============================

			if(!sbFound)
			{
				//no stockboy found so push button for help
				printf("Customer [%d] looked in all aisle for StockBoy. He is now requesting help by pressing service button.\n",threadId);
				noSBPushButtonLock->Acquire();

				//Incrementing the length for pushButton queue
				noSBPushButtonLineLength++;
				noSBPushButtonCV->Wait(noSBPushButtonLock);

				//Finding the StockBoy with -3 as the status ; this represents he is ready to serve the PushButton
				noSBPushButtonLock->Release();

				sbStatusLock->Acquire();
				for(int i=0;i<noOfStockBoys;i++)
				{
					if(sbStatus[i] == -3)
					{

						mySB = i;
						//Chaging the sbStatus back to default -1;so that no other can pick him up
						sbStatus[i]= -1;
						break;
					}
				}
				sbStatusLock->Release();			
				sbLock[mySB]->Acquire();			
				sbCustQA[mySB][0]=threadId;
				//Set the id of the item u want to ask the stock boy about.
				sbCustQA[mySB][1]=currentItemId;

				//Asking the Stockboy about item.
				sbCV[mySB]->Signal(sbLock[mySB]);
				sbCV[mySB]->Wait(sbLock[mySB]);
				sbLock[mySB]->Release();
			}
			//============PushButton Code ends here================

			else
			{

				sbLock[mySB]->Acquire();
				//Set Customer id for StockBoy to knw.
				sbCustQA[mySB][0]=threadId;
				//Set the id of the item u want to ask the stock boy abt.
				sbCustQA[mySB][1]=currentItemId;
				printf("Customer [%d] is asking for assistance from StockBoy [%d].\n",threadId,mySB);
				//Asking the Stockboy abt item.
				sbCV[mySB]->Signal(sbLock[mySB]);
				sbCV[mySB]->Wait(sbLock[mySB]);
				printf("Customer [%d] got aisle [%d] from StockBoy [%d].\n",threadId,itemAisleId,mySB);
				sbLock[mySB]->Release();
			}
			//====================StockBoy interaction code ends here.=====================

		} // end of item not found loop
		

		///////================Customer fetch the item code below============

		//Acquiring the lock on the aisle where the item has to be pickeup from.
		aisleQtyLock[itemAisleId]->Acquire();
		// checking if the aisleQty is 0 or not.
		if(aisleQty[itemAisleId]==0)
		{
			// If 0 then wait for the item to be restocked.
			aisleEmptyCV[itemAisleId]->Wait(aisleQtyLock[itemAisleId]);
		}
		//decrementing the Qty by 1.
		if(testcase == 9 )
		{
			printf("Customer [%d] is picking item of type [%d] from Aisle [%d].\n",threadId,customerData[threadId].itemsToBePurchased[currentItemId],itemAisleId);
		}

		aisleQty[itemAisleId]--;

		//Pushing the item to the list for restocking.
		reStockListLock->Acquire();
		restockItem = new int(customerData[threadId].itemsToBePurchased[currentItemId]);
		reStockList->Append((void *)restockItem);
		reStockListLock->Release();

		//Checking if more is available on Aisle to signal to the other Customers in case waiting for same item/aisle.
		if(aisleQty[itemAisleId]>0)
		{
			aisleEmptyCV[itemAisleId]->Signal(aisleQtyLock[itemAisleId]);
		}
		aisleQtyLock[itemAisleId]->Release();

		/////================Customer fetch the item code ends here==============


	} // end of customer item pickup loop


	///======================End of Customer Fetching all items code here====================


	/////======Finding shortest line and waiting checkout code below========================

liningForClerk://label for bypassing item finding code for customers returning items

	//Acquire the lock on clerkLine to find the Shortest line length maintaining the mutual exclusion
	clerkLineLock->Acquire();

findshortestline:
	//Find shortest line length and its index
	for(int i=0; i<noOfClerks; i++)
	{
		if(clerkStatus[i]==CLERK_ONBREAK)
		{
			//  If Clerk is on break than no need to check his line length.
			continue;
		}
		// Check and compare for finding minimum of line length and corrosponding index
		if(clerkLineLength[i]<shortestLineLength)
		{
			shortestLineLength=clerkLineLength[i];
			shortestLineIndex=i;
		}
	}

	//Case where all clerks and on break
	if(shortestLineIndex==-1)
	{
		//Alert the manager that all clerks are on break
		allClerksOnBreak=true;
		custWaitingCV->Wait(clerkLineLock);
		goto findshortestline;

	}

	///==============Shortest Line found. Waiting for checkout==================

	//If customer finds a line with shortest length that has a clerk who is not on break,
	// increment the line length
	printf("Customer [%d] chose Clerk [%d] with line length of [%d].\n",threadId,shortestLineIndex,clerkLineLength[shortestLineIndex]);	
	clerkLineLength[shortestLineIndex]++;
	clerkLineCV[shortestLineIndex]->Wait(clerkLineLock);
	
	//decrease the line length as the one customer will now be served by the clerk.
	clerkLineLength[shortestLineIndex]--;
	clerkLineLock->Release();

	//Acquire lock on that clerk so that the checkout process is mutually exclusive.
	clerkLock[shortestLineIndex]->Acquire();

	// Give the clerk items one by one.
	customerId[shortestLineIndex]=threadId;
	//notify the clerk whether the customer is buying or returning items
	isCustomerReturning[shortestLineIndex]=customerData[threadId].customerReturning;
	

	////////=================Entire CheckOut code below===========================

	for(int i=0;i<customerData[threadId].noOfItemsToBePurchased;i++)
	{

		// Setting the id of item passed for the clerk to access
		itemId[shortestLineIndex]=customerData[threadId].itemsToBePurchased[i];

		//Checking for the last item in order to notify the clerk.
		if(i==(customerData[threadId].noOfItemsToBePurchased)-1)
		{
			lastItem[shortestLineIndex]=TRUE;
			
		}
		// customer will give items one by one to clerk
		printf("Customer [%d] gives item [%d] to Clerk [%d].\n",threadId,(i+1),shortestLineIndex);
		clerkTalkCV[shortestLineIndex]->Signal(clerkLock[shortestLineIndex]);
		if(i==(customerData[threadId].noOfItemsToBePurchased)-1)
		{
			printf("Customer [%d] tells Clerk [%d], I have given you all my [%d] items.\n",threadId,shortestLineIndex,customerData[threadId].noOfItemsToBePurchased);
		}
		clerkTalkCV[shortestLineIndex]->Wait(clerkLock[shortestLineIndex]);
	}
	if(!customerData[threadId].customerReturning){
		printf("Customer [%d] pays $[%d] to Clerk [%d] and is now waiting for receipt.\n",threadId,receiptBillAmount[shortestLineIndex],shortestLineIndex);
		//Signal the clerk for payment.
		clerkTalkCV[shortestLineIndex]->Signal(clerkLock[shortestLineIndex]);
		clerkTalkCV[shortestLineIndex]->Wait(clerkLock[shortestLineIndex]);
		printf("Customer [%d] got receipt from Clerk [%d] and is now leaving.\n",threadId,shortestLineIndex);
	}
	else{
		printf("Customer [%d] receives $[%d] from Clerk [%d] and is now waiting for receipt.\n",threadId,receiptBillAmount[shortestLineIndex],shortestLineIndex);
		//Signal the clerk for payment.
		clerkTalkCV[shortestLineIndex]->Signal(clerkLock[shortestLineIndex]);
		clerkTalkCV[shortestLineIndex]->Wait(clerkLock[shortestLineIndex]);
		printf("Customer [%d] got receipt from Clerk [%d] and is now leaving.\n",threadId,shortestLineIndex);
	}

////=============CheckOut Over. Customer thread will end soon after reseting values=============///

	//Reseting the values to defaults
	lastItem[shortestLineIndex]=FALSE;
	itemId[shortestLineIndex]=-1;
	customerId[shortestLineIndex]=-1;
	isCustomerReturning[shortestLineIndex]=FALSE;
	clerkLock[shortestLineIndex]->Release();
	totalcustomersexited++;
	
}

///============End of Customer Thread Code==================///


///=================Cash Register Thread Starts here=========////

void CashReg(int threadId)
{
	while(1)
	{

		//========Clerk Cash Register Checkout code below=======
		clerkLock[threadId]->Acquire();
		if(cashRegisterStatus[threadId] == CLERK_WAITING){
			cashRegisterCV[threadId]->Signal(clerkLock[threadId]);
			cashRegisterCV[threadId]->Wait(clerkLock[threadId]);
		}
		else{
			cashRegisterStatus[threadId] = CASHREG_WAITING;
			cashRegisterCV[threadId]->Wait(clerkLock[threadId]);
		}
		int counter=1;
		//cashRegister is interacting with the clerk for customer billing

		while(!lastItem[threadId])
		{
			printf("Cash Register [%d] got item [%d] from Clerk [%d] to scan.\n",threadId,counter,threadId);
			counter++;
			cashRegister[threadId].customerAmount = cashRegister[threadId].customerAmount + itemsInStoreInfo[itemId[threadId]];
			cashRegisterCV[threadId]->Signal(clerkLock[threadId]);
			cashRegisterCV[threadId]->Wait(clerkLock[threadId]);
		}

		printf("Cash Register [%d] got item [%d] from Clerk [%d] to scan.\n",threadId,counter,threadId);
		//Add the last item to the total of the customer total amount
		cashRegister[threadId].customerAmount = cashRegister[threadId].customerAmount + itemsInStoreInfo[itemId[threadId]];
		printf("Cash Register [%d] has scanned all [%d] items for Customer [%d].\n",threadId,counter,customerId[threadId]);
		
		if(isCustomerReturning[threadId]){//customer returning items
			//=========get money from Manager
			manager_CashRegisterLock[threadId]->Acquire();
			cashRegister[threadId].totalSalesAtCashRegister = cashRegister[threadId].totalSalesAtCashRegister - cashRegister[threadId].customerAmount;
			amountNeeded[threadId]=(cashRegister[threadId].customerAmount);
			printf("Cash Register [%d] informed the manager that he needs $[%d].\n",threadId, amountNeeded[threadId]);
			cashRegisterWaitingCV[threadId]->Wait(manager_CashRegisterLock[threadId]);//waiting for money from manager
			printf("Cash Register [%d] received $[%d] from the manager.\n", threadId, amountNeeded[threadId]);
			//========Received cash from Manager
			amountNeeded[threadId] = 0;
			manager_CashRegisterLock[threadId]->Release();
			//Clerk would be giving the final amount to the customer from this receiptBillAmount
			printf("Cash Register [%d] gave total cost $[%d] for Customer [%d] to Clerk [%d] for [%d] items.\n",threadId,cashRegister[threadId].customerAmount,customerId[threadId],threadId,counter);
			printf("Cash Register [%d] gave the money to Clerk [%d].\n",threadId,threadId);
			receiptBillAmount[threadId] = cashRegister[threadId].customerAmount;
			cashRegisterCV[threadId]->Signal(clerkLock[threadId]);
			cashRegisterCV[threadId]->Wait(clerkLock[threadId]);

			//Give the receipt
			cashRegister[threadId].customerAmount = 0;
			cashRegisterCV[threadId]->Signal(clerkLock[threadId]);
			printf("Cash Register [%d] gave receipt to Clerk [%d] for Customer [%d].\n",threadId,threadId,customerId[threadId]);
			cashRegisterStatus[threadId] = NOT_SET;

		}
		else{//customer buying items
			//Clerk would be getting the final amount for the customer from this receiptBillAmount
			printf("Cash Register [%d] gave total cost $[%d] for Customer [%d] to Clerk [%d] for [%d] items.\n",threadId,cashRegister[threadId].customerAmount,customerId[threadId],threadId,counter);
			receiptBillAmount[threadId] = cashRegister[threadId].customerAmount;
			cashRegisterCV[threadId]->Signal(clerkLock[threadId]);
			cashRegisterCV[threadId]->Wait(clerkLock[threadId]);

			//If I'm here I've got the payment
			manager_CashRegisterLock[threadId]->Acquire();
			cashRegister[threadId].totalAmount = cashRegister[threadId].totalAmount + cashRegister[threadId].customerAmount;
			cashRegister[threadId].totalSalesAtCashRegister = cashRegister[threadId].totalSalesAtCashRegister + cashRegister[threadId].customerAmount;
			manager_CashRegisterLock[threadId]->Release();

			cashRegister[threadId].customerAmount = 0;
			printf("Cash Register [%d] got the money from Clerk [%d].\n",threadId,threadId);
			cashRegisterCV[threadId]->Signal(clerkLock[threadId]);
			printf("Cash Register [%d] gave receipt to Clerk [%d] for Customer [%d].\n",threadId,threadId,customerId[threadId]);
			cashRegisterStatus[threadId] = NOT_SET;
	}

		//print the total sales till this point
		manager_CashRegisterLock[threadId]->Acquire();
		printf("Cash Register [%d] total sale is $[%d].\n",threadId,cashRegister[threadId].totalSalesAtCashRegister);
		manager_CashRegisterLock[threadId]->Release();

		clerkLock[threadId]->Release();
	}

}

////////===================Cash Register thread code ends here==============//////



//////===============Clerk thread starts here==================////
void Clerk(int threadId)
{

	//Clerk thread buying some time before customer's finish purchasing
	for(int i=0; i<10; i++){
		currentThread->Yield();
	}
	//storing clerk number on index i
	int myId = threadId;
	while(1)
	{
		// Acquire clerkLineLock
		clerkLineLock->Acquire();
		//========this infinite loop is for clerk to check on the customerlinelength after coming from a break
		while(1)
		{
			//If there are customers waiting for the clerk, then service them.
			//else go on a break
			if(clerkLineLength[myId]>0){//Customers waiting for me

				//if mylinelength>4 inform the manager to wake up another clerk
				if(clerkLineLength[myId]>3)
				{
					wakeUpAClerk=true;
					signalingClerk=threadId;
					printf("Clerk [%d] sees more than 4 people in line and calls Manager.\n",threadId);
				}
				//Wake 1 customer up
				clerkLineCV[myId]->Signal(clerkLineLock);
				clerkStatus[myId] = CLERK_BUSY;
				break;
			}
			else{// No customer waiting for me. Go on a break
				clerkStatus[myId] = CLERK_ONBREAK;
				printf("Clerk [%d] is leaving Cash Register [%d] and going on break.\n",threadId,threadId);
				clerkOnBreakCV->Wait(clerkLineLock);
				printf("Clerk [%d] was called by Manager to work.\n",threadId);
				clerkStatus[myId] = CLERK_COMING_FROM_BREAK;

				//Wake up all customers waiting for me
				custWaitingCV->Broadcast(clerkLineLock);
				clerkStatus[myId] = CLERK_FREE;
				clerkLineLock->Release();
				//buy some time
				for(int i=0; i<10; i++){
					currentThread->Yield();
				}
				clerkLineLock->Acquire();
				continue;
			}
		}
		//Very important to do this. Lock clerkLock before releasing clerkLineLock so that the transition between monitor
		//is smooth. This makes sure the clerk acquires the monitor variables before the customer does. Otherwise it may
		// lead to a deadlock if the clerk above signal to the customer is lost
		
		///=============Clerk Checkout code below=======================///
		clerkLock[myId]->Acquire();
		clerkLineLock->Release();
		clerkTalkCV[myId]->Wait(clerkLock[myId]);// Time to play some tennis

		//-------------------------------------------------------------------------
		//  Customer has signaled me. Ball is in my court
		//Setup Interaction with Cash Register
		if(cashRegisterStatus[myId]!=CASHREG_WAITING){//if Cash register is not waiting then i wait
			cashRegisterStatus[myId]=CLERK_WAITING;
			cashRegisterCV[myId]->Wait(clerkLock[myId]);
		}

		//Customer has given an item for me to be scanned
		int item=0; // index to keep track of item number
		while(!lastItem[myId]){
			printf("Clerk [%d] got item [%d] from Customer [%d].\n", myId, item, customerId[myId]);
			
			//Passing the baton to Cash Register
			printf("Clerk [%d] gave item [%d] to Cash Register [%d] for scanning.\n",threadId,item,threadId);
			item++;
			cashRegisterCV[myId]->Signal(clerkLock[myId]);
			cashRegisterCV[myId]->Wait(clerkLock[myId]);
			//Asking Customer to scan the next item
			clerkTalkCV[myId]->Signal(clerkLock[myId]);
			clerkTalkCV[myId]->Wait(clerkLock[myId]);
		}
		//Passing the baton to Cash Register for the last item
		printf("Clerk [%d] got item [%d] from Customer [%d].\n", myId, item, customerId[myId]);
		printf("Clerk [%d] gave item [%d] to Cash Register [%d] for scanning.\n",threadId,item,threadId);

		cashRegisterCV[myId]->Signal(clerkLock[myId]);
		cashRegisterCV[myId]->Wait(clerkLock[myId]);
		printf("Clerk [%d] got total cost $[%d] from Cash Register [%d].\n",threadId,receiptBillAmount[threadId],threadId);
		//Passing the bill to the customer
		printf("Clerk [%d] tells Customer [%d] total cost is $[%d].\n", myId,customerId[myId],receiptBillAmount[threadId]);
		if(isCustomerReturning[threadId]){//returning customer
			printf("Clerk [%d] got money $[%d] from Cash Register [%d].\n", myId, receiptBillAmount[threadId], myId);
			printf("Clerk [%d] gave the money $[%d] to Customer [%d].\n", myId, receiptBillAmount[threadId], customerId[myId]);
		}
		clerkTalkCV[myId]->Signal(clerkLock[myId]);
		clerkTalkCV[myId]->Wait(clerkLock[myId]);
		//Got Money from Customer. Give it to cash register
		if(!isCustomerReturning[threadId]){//buying customer
			printf("Clerk [%d] got money $[%d] from Customer [%d].\n",threadId,receiptBillAmount[threadId],customerId[myId]);
			printf("Clerk [%d] gave the money $[%d] to Cash Register [%d].\n",threadId,receiptBillAmount[threadId],threadId);
		}
		cashRegisterCV[myId]->Signal(clerkLock[myId]);
		cashRegisterCV[myId]->Wait(clerkLock[myId]);
		printf("Clerk [%d] got receipt from Cash Register [%d].\n",threadId,threadId);
		//Got Receipt from Cash Register. Give it to Customer
		printf("Clerk [%d] gave the receipt to Customer [%d] and tells him to leave.\n",threadId,customerId[myId]);
		clerkTalkCV[myId]->Signal(clerkLock[myId]);
		clerkLock[myId]->Release();
		//////==============Clerk checkout code ends here=======================
		//Setting clerk status to free. waiting for other customer or will go on break.
		clerkLineLock->Acquire();
		clerkStatus[myId] = CLERK_FREE;
		clerkLineLock->Release();

	}
}
////=================Clerk thread code ends here=================///////////

//////===============Manager Thread Code will start here=========//////////

void Manager(int threadId)
{
	int totalSales=0;
	//Manager will check for end of simulation when all customer have left the Depot.
	while(totalcustomersexited != noOfCustomers){//this checks for end of simulation
		//Wakeup clerks if they are on break and customer needs them
		clerkLineLock->Acquire();
		//Will wake up ALL clerk if all are on break and customers waiting.
		if(allClerksOnBreak){

			allClerksOnBreak=false;
			clerkOnBreakCV->Broadcast(clerkLineLock);
		}
		//will wake up a clerk of clerk siganls that some line length is more than 4.
		else if(wakeUpAClerk){
			printf("Manager got a call from Clerk [%d].\n",signalingClerk);
			wakeUpAClerk = false;
			clerkOnBreakCV->Signal(clerkLineLock);
			printf("Manager wakes up Clerk.\n");
		}
		clerkLineLock->Release();

		//Empty the Cash Register and display the total sales till that point of time.
		//Will take cash out only randomly from all cash registers.
		int takeCashProb=(rand()%5);
		if(takeCashProb == 4)
		{
			for(int i=0; i<noOfCashReg; i++){

				manager_CashRegisterLock[i]->Acquire();
				if(amountNeeded[i]>0){
					totalSales = totalSales - amountNeeded[i];
					printf("Manager gave $[%d] to cash register [%d].\n", amountNeeded[i], i);
					cashRegisterWaitingCV[i]->Signal(manager_CashRegisterLock[i]);
				}
				totalSales = totalSales + cashRegister[i].totalAmount;
				if(rand()%10==9){
					printf("Manager emptied Cash Register [%d] drawer.\n",i);
					printf("Manager has total sale of $[%d].\n", totalSales);
					printf("Cash Register [%d] drawer is emptied by Manager.\n",i);
					printf("Cash Register [%d] total sale until now is $[%d].\n",i,cashRegister[i].totalSalesAtCashRegister);
				}
				cashRegister[i].totalAmount=0;
				manager_CashRegisterLock[i]->Release();
			}
			if(rand()%25==20){
				printf("-------Total Sale of the entire store until now is $[%d]---------\n",totalSales);
			}
		}
		//Wakeup StockBoys if they are on break and they are needed by some customers
		noSBPushButtonLock->Acquire();
		if(noSBPushButtonLineLength>0){//wake up a stock boy
			printf("Manager wakes up StockBoy.\n");
			sbOnBreakCV->Signal(noSBPushButtonLock);
		}
		noSBPushButtonLock->Release();

		// manager will check if there are items to be restocked. if yes he will wake up all stock boys on break.
		reStockListLock->Acquire();
		if(!(reStockList->IsEmpty())){
			reStockListLock->Release();
			noSBPushButtonLock->Acquire();
			sbOnBreakCV->Broadcast(noSBPushButtonLock);
			noSBPushButtonLock->Release();
		}
		reStockListLock->Release();
		currentThread->Yield();
	}///end of while
	//Empty the cash register drawers
	for(int i=0; i<noOfCashReg; i++){
			manager_CashRegisterLock[i]->Acquire();
			totalSales = totalSales + cashRegister[i].totalAmount;
			cashRegister[i].totalAmount=0;
			manager_CashRegisterLock[i]->Release();
		}
	//Print out the total sales of individual cash register
	for(int i=0; i<noOfCashReg; i++){
		manager_CashRegisterLock[i]->Acquire();
			printf("Total Sale from Cash Register [%d] is $[%d].\n",i,cashRegister[i].totalSalesAtCashRegister);
		manager_CashRegisterLock[i]->Release();
	}

	////#####################Simulation ends when code will reach here###################////////
	printf("Total Sale of the entire store is $[%d].\n",totalSales);
}
///=========Manager thread will end here==========//

///=========StockBoy thread will begin here===========//
void StockBoy(int threadId)
{
	int myId = threadId;
	int *restockItem;//pointer to hold restockItem
	//Stockboy thread buying some time for customers to buy items
	for(int i=0; i<3; i++)
	{
		currentThread->Yield();
	}

	while(1)
	{
		int myaisle=-1;	// index to know the aisle that i need to restock
		reStockListLock->Acquire();
		printf("StockBoy [%d] is checking if more items are to be re-stocked.\n",myId);
		if(!(reStockList->IsEmpty()))//if restock list is not empty then go to the stock room to get the item
		{
			restockItem = (int *)reStockList->Remove();
			myaisle =*restockItem;//Remove the item to be restocked from the list
			delete restockItem;
			reStockListLock->Release();

			printf("StockBoy [%d] goes back to stock room for item [%d].\n",myId,myaisle);
			//Get into the stock room to obtain the item
			stockRoomLock->Acquire();
			if(stockRoomStatus==-1){
				stockRoomStatus=myId;
			}
			else{
				printf("StockBoy [%d] is waiting for StockBoy [%d] to leave the stock room.\n",myId, stockRoomStatus);
				stockRoomWaitCV->Wait(stockRoomLock);
			}
			stockRoomLock->Release();
			//Spend some time in the stock room
			printf("StockBoy [%d] is in stock room.\n",threadId);
			for(int i=0; i<2; i++)
			{
					currentThread->Yield();
			}
			printf("StockBoy [%d] retrieve one new item [%d] from stock room.\n",threadId,myaisle);
			printf("StockBoy [%d] leaves stock room.\n",threadId);
			stockRoomLock->Acquire();
			stockRoomWaitCV->Signal(stockRoomLock);
			stockRoomStatus = -1;
			stockRoomLock->Release();
			//Out of the stock room
		}
		

		if(myaisle==-1)//There is nothing to restock
		{
			reStockListLock->Release();//if no item to restock, release restock list
			sbStatusLock->Acquire();
			printf("StockBoy [%d] is going on break.\n",threadId);
			sbStatus[myId]=-2;//off to break
			
			sbStatusLock->Release();
			
			//on break
			noSBPushButtonLock->Acquire();
			sbOnBreakCV->Wait(noSBPushButtonLock);
			printf("StockBoy [%d] got call from Manager.\n",threadId);
			noSBPushButtonLock->Release();
			
			//Back to work
			sbStatusLock->Acquire();
			sbStatus[myId]=-1;//default state
			sbStatusLock->Release();
			
			// coming back from break
			noSBPushButtonLock->Acquire();
			while(noSBPushButtonLineLength>0){
				noSBPushButtonLineLength--;
				noSBPushButtonCV->Signal(noSBPushButtonLock);
				sbStatusLock->Acquire();
				sbStatus[myId]=-3;
				sbLock[myId]->Acquire();				
				sbStatusLock->Release();
				noSBPushButtonLock->Release();
				sbCV[myId]->Wait(sbLock[myId]);
				//Ping-Pong
				
				sbCV[myId]->Signal(sbLock[myId]);
				sbLock[myId]->Release();

				noSBPushButtonLock->Acquire();//Acquire this lock for the while loop
			}
			noSBPushButtonLock->Release();
			continue;//start from the infinite while loop
		}//end of (if(myaisle==-1))

		else//I have to restock an item
		{
			//change my status to the aisle i am in
			sbStatusLock->Acquire();
			sbStatus[myId]=myaisle;
			sbStatusLock->Release();
			
			//Spending some time in the aisle			
			for(int i=0; i<10; i++)
			{
				currentThread->Yield();
			}
			//Restock the item;
			aisleQtyLock[myaisle]->Acquire();
			if(testcase == 9 )
			{
				printf("Stockboy [%d] is restocking item [%d] on Aisle [%d].\n",threadId,myaisle,myaisle);
			}
			aisleQty[myaisle]++;
			aisleEmptyCV[myaisle]->Signal(aisleQtyLock[myaisle]);//If any customer is waiting for an item, then signal him
			aisleQtyLock[myaisle]->Release();

			//See if any customer is waiting for my service
			sbStatusLock->Acquire();
			while(aisleHelpLineLength[myaisle]>0)
			{
				aisleHelpCV[myaisle]->Signal(sbStatusLock);
				aisleHelpLineLength[myaisle]--;	//Decrement the aisle length
				sbStatus[myId]= sbStatus[myId] + MAX_NO_OF_AISLE;//increment to signal customer that i am free
				sbLock[myId]->Acquire();
				sbStatusLock->Release();
				sbCV[myId]->Wait(sbLock[myId]);
				printf("StockBoy [%d] is approached by Customer [%d] for assistance.\n",threadId,sbCustQA[myId][0]);
				//Time to play ping pong
				printf("StockBoy [%d] gave aisle [%d] to Customer [%d] for item [%d].\n",threadId,sbCustQA[myId][1],sbCustQA[myId][0],sbCustQA[myId][1]);
				sbCV[myId]->Signal(sbLock[myId]);
				sbLock[myId]->Release();				

				//Acquire sbStatusLock again for the while
				sbStatusLock->Acquire();
			}
			//end of customer service
			sbStatus[myId]=-1;
			sbStatusLock->Release();
		}//end of else block of restocking and customer service
	}//end of infinite while loop
}//end of function

///===Stock Boy thread ends here================//





//============================================
//  Functions for the repeatable test cases
//============================================


//This part of the code generates the common test parameters needed for the simulation to run
// i.e. Condition Variables , Monitors & Locks
void generateCmnTestParams()
{
	Thread* t;
	char* name;
	




	printf("\n\nNumber of Clerks = [%d]\n",noOfClerks);
	printf("Number of StockBoys = [%d]\n",noOfStockBoys);
	printf("Number of CashRegisters = [%d]\n",noOfCashReg);
	printf("Number of Customers = [%d]\n",noOfCustomers);
	printf("Number of Managers = [1]\n");
	printf("Number of Aisle = [10]\n");
    printf("Items:\n");
    printf("\tNumber - Price\n");
	for(int j=0;j<MAX_NO_OF_AISLE;j++)
	{
		printf("\t%d  -  %d  \n",j,itemsInStoreInfo[j]);
	}
    printf("\n\n");


	int i=0;
	reStockList = new List();//List for restocking;
	clerkLineLock= new Lock("clerkLineLock");	
	sbStatusLock = new Lock("sbStatusLock");
	stockRoomLock = new Lock("stockRoomLock");
	stockRoomWaitCV = new Condition("stockRoomWaitCV");
	reStockListLock = new Lock("reStockListLock");
	custWaitingCV = new Condition("custWaitingCV");
	for(i=0;i<MAX_NO_OF_AISLE;i++)
	{
		name = new char[100];
		sprintf(name,"aisleQtyLock%d",i);
		aisleQtyLock[i]=new Lock(name);

		aisleQty[i]=3;
		name = new char[100];
		sprintf(name,"aisleEmptyCV%d",i);
		aisleEmptyCV[i]=new Condition(name);

		name = new char[100];
		sprintf(name,"aisleHelpCV%d",i);
		aisleHelpCV[i]=new Condition(name);
	}

	noSBPushButtonLock = new Lock("noSBPushButtonLock");
	noSBPushButtonCV = new Condition("noSBPushButtonCV");
	noSBPushButtonLineLength=0;

	sbOnBreakCV = new Condition("sbOnBreakCV");
	for(i=0;i<noOfStockBoys;i++)
	{
		sbStatus[i]=-1;
		name = new char[100];
		sprintf(name,"sbLock%d",i);
		sbLock[i]=new Lock(name);
		
		name = new char[100];
		sprintf(name,"sbCV%d",i);
		sbCV[i]=new Condition(name);

	}
	for(i=0;i<noOfClerks;i++)
	{	
		name = new char[100];
		sprintf(name,"clerkLock%d",i);
		clerkLock[i]=new Lock(name);

		name = new char[100];
		sprintf(name,"clerkLineCV%d",i);
		clerkLineCV[i]=new Condition(name);

		name = new char[100];
		sprintf(name,"clerkTalkCV%d",i);
		clerkTalkCV[i]=new Condition(name);
	}

	for(i=0;i<noOfCashReg;i++)
	{
		name = new char[100];
		sprintf(name,"cashRegisterCV%d",i);
		cashRegisterCV[i]=new Condition(name);

		name = new char[100];
		sprintf(name,"manager_CashRegisterLock%d",i);
		manager_CashRegisterLock[i]=new Lock(name);

		name = new char[100];
		sprintf(name,"cashRegisterWaitingCV%d",i);
		cashRegisterWaitingCV[i] = new Condition(name);
	}

	noClerkButtonCV= new Condition("noClerkButtonCV");

	clerkOnBreakCV=new Condition("clerkOnBreakCV");

	name = new char[100];
	sprintf(name,"Manager%d",0);
	t = new Thread(name);
	t->Fork((VoidFunctionPtr)Manager,0);

	for(i=0;i<noOfStockBoys;i++)
	{
		name = new char[100];
		sprintf(name,"StockBoy%d",i);
		t = new Thread(name);
		t->Fork((VoidFunctionPtr)StockBoy,i);
	}

	for(i=0;i<noOfCustomers;i++)
	{
		name = new char[100];
		sprintf(name,"Customer%d",i);
		t = new Thread(name);
		t->Fork((VoidFunctionPtr)Customer,i);
	}


	for(i=0;i<noOfClerks;i++)
	{
		name = new char[100];
		sprintf(name,"Clerk%d",i);
		t = new Thread(name);
		t->Fork((VoidFunctionPtr)Clerk,i);
	}

	for(i=0;i<noOfCashReg;i++)
	{
		name = new char[100];
		sprintf(name,"CashRegister%d",i);
		t = new Thread(name);
		t->Fork((VoidFunctionPtr)CashReg,i);
	}


}

// Gets the user input for the noOfcustomers , noOfClerks, noOfCashregisters and validates the input
void getUserInput()
{
	
	printf("\nEnter the no of Clerks & Cash Registers:");
	scanf("%d",&noOfClerks);

	if(noOfClerks>MAX_NO_OF_CLERKS || noOfClerks<0)
	{
		printf("\n---------------------------------------------------------------------------------");
		printf("\nValue for no of clerks INVALID. Enter value btw 1 and 5. Program will exit now...");
		printf("\n---------------------------------------------------------------------------------\n");
		return;
	}

	printf("\nEnter the no of Customers: ");
	scanf("%d",&noOfCustomers);
	noOfCashReg=noOfClerks;

	if(noOfCustomers>MAX_NO_OF_CUSTOMERS || noOfCustomers<20)
	{
		printf("\n---------------------------------------------------------------------------------");
		printf("\n Value for no of customers INVALID. Enter value btw 20 and %d. Program will exit now...",MAX_NO_OF_CUSTOMERS);
		printf("\n---------------------------------------------------------------------------------\n");
		return;
	}

	printf("\nEnter the no of Stock Boys: ");
	scanf("%d",&noOfStockBoys);	
	
	
	if(noOfStockBoys>MAX_NO_SB || noOfStockBoys<3)
	{
		printf("\n---------------------------------------------------------------------------------");
		printf("\n Value for no of StockBoys INVALID. Enter value btw 3 and %d. Program will exit now...",MAX_NO_SB);
		printf("\n---------------------------------------------------------------------------------\n");
		return;
	}

	generateCmnTestParams();

}

void testcase1()
{
	//printf("Test case 1 started: \n");
	
	noOfClerks=3;
	noOfCashReg=3;
	noOfCustomers=10;
	noOfStockBoys=5;

	for (int i=0;i<noOfCustomers;i++ )
	{
		customerData[i].noOfItemsToBePurchased = 1;
	}

	generateCmnTestParams();

}
void testcase2()
{
	//printf("Test case 2 started: \n");
	noOfClerks=3;
	noOfCashReg=3;
	noOfCustomers=10;
	noOfStockBoys=5;

	generateCmnTestParams();

}
void testcase3()
{
	//printf("Test case 3 started: \n");
	noOfClerks=3;
	noOfCashReg=3;
	noOfCustomers=10;
	noOfStockBoys=5;

	generateCmnTestParams();

}
void testcase4()
{
	//printf("Test case 4 started: \n");
	noOfClerks=1;
	noOfCashReg=1;
	noOfCustomers=1;
	noOfStockBoys=1;

	for (int i=0;i<noOfCustomers;i++ )
	{
		customerData[i].noOfItemsToBePurchased = 3;
	}

	generateCmnTestParams();

}
void testcase5()
{
	//printf("Test case 5 started: \n");
	noOfClerks=1;
	noOfCashReg=1;
	noOfCustomers=2;
	noOfStockBoys=1;

	for (int i=0;i<noOfCustomers;i++ )
	{
		customerData[i].noOfItemsToBePurchased = 2;
	}

	generateCmnTestParams();

}
void testcase6()
{
	//printf("Test case 6 started: \n");
	noOfClerks=5;
	noOfCashReg=5;
	noOfCustomers=1;
	noOfStockBoys=1;

	for (int i=0;i<noOfCustomers;i++ )
	{
		customerData[i].noOfItemsToBePurchased = 2;
	}

	generateCmnTestParams();

}
void testcase7()
{
	//printf("Test case 7 started: \n");
	noOfClerks=2;
	noOfCashReg=2;
	noOfCustomers=15;
	noOfStockBoys=5;

	generateCmnTestParams();

}
void testcase8()
{
	//printf("Test case 8 started: \n");
	noOfClerks=2;
	noOfCashReg=2;
	noOfCustomers=2;
	noOfStockBoys=1;

	generateCmnTestParams();

}
void testcase9()
{
	//printf("Test case 9 started: \n");
	noOfClerks=3;
	noOfCashReg=3;
	noOfCustomers=3;
	noOfStockBoys=2;

	generateCmnTestParams();

}
void testcase10()
{
	//printf("Test case 10 started: \n");
	noOfClerks=3;
	noOfCashReg=3;
	noOfCustomers=2;
	noOfStockBoys=3;

	for (int i=0;i<noOfCustomers;i++ )
	{
		customerData[i].noOfItemsToBePurchased = 3;
	}

	generateCmnTestParams();

}
void testcase11()
{
	//printf("Test case 11 started: \n");
	noOfClerks=3;
	noOfCashReg=3;
	noOfCustomers=6;
	noOfStockBoys=3;

	generateCmnTestParams();
}

//This test case runs the entire simulation with minimum requirements
void testcase12()
{

	
	noOfClerks=5;
	noOfCashReg=5;
	noOfCustomers=20;
	noOfStockBoys=3;

	generateCmnTestParams();
}

//This test case is used for running entire simulation with -rs option
void testcase13()
{

	getUserInput();

}



//====================================================================================
// Function Problem2() which is called for simulation of the Part 2 of Assignment 1
// Contains the Test Case Selection Menu in it.
//====================================================================================


void Problem2()
{
	Thread *t;
	char *name;

	printf("\n Test Case Menu: Please enter a value from the following for the appropriate test case\n");
	printf(" 1. Customers always take the shortest line, but no 2 customers ever choose the same shortest line at the same time\n");
	printf(" 2. Managers can only talk to one Cash Register at a time.\n");
	printf(" 3. Customers do not leave until they are given their receipt by the Clerk. The Clerk does not start on another customer until they know that the last Customer has left their area\n");
	printf(" 4. Customers \"hand\" each item to the Clerk, only after the Clerk has scanned the previous item and they are ready for another item.\n");
	printf(" 5. Customers don't try to hand an item to the Clerk until the Clerk has scanned the previous item.\n");
	printf(" 6. Clerks go on break when they have no one waiting in their line.\n");
	printf(" 7. Managers get Clerks off their break when lines get too long.\n"); 
	printf(" 8. Total sales never suffers from a race condition.\n"); 
	printf(" 9. StockBoys don't try to restock an item on a shelf when a Customer is trying to take an item off the shelf.\n"); 
	printf("10. Only one StockBoy enters the stock room at a time.\n"); 
	printf("11. StockBoys only help one Customer at a time.\n"); 
	printf("12. General simulation with minimum requirements : \n"); 
	printf("13. General Simulation with user input values : \n"); 

	printf("\nEnter Test Case Number:  ");
	scanf("%d",&testcase);

	switch(testcase)
	{
	case 1:
		testcase1();
		break;
	case 2:
		testcase2();
		break;
	case 3:
		testcase3();
		break;
	case 4:
		testcase4();
		break;
	case 5:
		testcase5();
		break;
	case 6:
		testcase6();
		break;
	case 7:
		testcase7();
		break;
	case 8:
		testcase8();
		break;
	case 9:
		testcase9();
		break;
	case 10:
		testcase10();
		break;
	case 11:
		testcase11();
		break;
	case 12:
		testcase12();
		break;
	case 13:
		testcase13();
		break;
	default:
		//printf("\n\n Entering Dummy TestCase\n\n");
		//testcase12();
		printf("\n\n\tPlease enter a valid test case number for nachos command\n\n\n");
	}

}
